| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- 'use client';
- import { useState } from 'react';
- import Link from 'next/link';
- import { BadgeCheck, Shield, MoreHorizontal, Pencil, Flag, Link as LinkIcon } from 'lucide-react';
- import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger
- } from '@/components/ui/dropdown-menu';
- import FollowButton from '@/app/component/FollowButton';
- import NoteButton from '@/app/(main)/note/_components/NoteButton';
- import { UserProfileDto } from '@/types/account/profile';
- import { buildChannelUrl, formatHandle } from '@/lib/utils/channel';
- import UserProfileEditDialog from './UserProfileEditDialog';
- type Props = {
- profile: UserProfileDto;
- };
- function formatCount(n: number): string {
- if (n >= 10000) return `${(n / 10000).toFixed(n >= 100000 ? 0 : 1)}만`;
- if (n >= 1000) return `${(n / 1000).toFixed(1)}천`;
- return n.toLocaleString();
- }
- export default function UserProfileHeader({ profile }: Props)
- {
- const [editOpen, setEditOpen] = useState(false);
- const displayName = profile.name || profile.memberSID;
- const avatarInitial = (displayName.charAt(0) || '?').toUpperCase();
- const handle = profile.channelHandle ? formatHandle(profile.channelHandle) : `@${profile.memberSID}`;
- const handleShare = async () =>
- {
- const url = `${window.location.origin}/user/${profile.memberSID}`;
- try {
- await navigator.clipboard.writeText(url);
- alert('프로필 링크가 복사되었습니다.');
- } catch {
- prompt('링크를 복사하세요:', url);
- }
- };
- return (
- <header className="user-profile__header">
- <div className="user-profile__banner">
- {profile.bannerUrl ? (
- <img src={profile.bannerUrl} alt={`${displayName} 배너`} />
- ) : (
- <div className="user-profile__banner-placeholder" />
- )}
- </div>
- <div className="user-profile__identity">
- <div className="user-profile__avatar-wrap">
- {profile.thumb ? (
- <img src={profile.thumb} alt={displayName} className="user-profile__avatar" />
- ) : (
- <span className="user-profile__avatar">
- <span className="user-profile__avatar-fallback">{avatarInitial}</span>
- </span>
- )}
- </div>
- <div className="user-profile__actions">
- {profile.isSelf ? (
- <>
- <button type="button" className="user-profile__edit-btn" onClick={() => setEditOpen(true)}>
- <Pencil size={14} /> 편집
- </button>
- <UserProfileEditDialog
- open={editOpen}
- onOpenChange={setEditOpen}
- profile={profile}
- />
- </>
- ) : (
- <>
- <FollowButton memberSID={profile.memberSID} initialFollowing={profile.isFollowing} />
- <NoteButton
- target={{ memberID: profile.memberID, displayName: displayName, thumbnailUrl: profile.thumb }}
- className="user-profile__note-btn"
- />
- </>
- )}
- <DropdownMenu>
- <DropdownMenuTrigger asChild>
- <button type="button" className="user-profile__more-btn" aria-label="더보기">
- <MoreHorizontal size={18} />
- </button>
- </DropdownMenuTrigger>
- <DropdownMenuContent align="end">
- <DropdownMenuItem onClick={handleShare}>
- <LinkIcon size={14} className="mr-2" /> 프로필 주소 복사
- </DropdownMenuItem>
- {!profile.isSelf && (
- <DropdownMenuItem>
- <Flag size={14} className="mr-2" /> 신고하기
- </DropdownMenuItem>
- )}
- </DropdownMenuContent>
- </DropdownMenu>
- </div>
- </div>
- <div className="user-profile__info">
- <h1 className="user-profile__name">
- {displayName}
- {profile.isCreator && (
- <span className="user-profile__badge user-profile__badge--creator" title="크리에이터">
- <BadgeCheck size={18} fill="currentColor" stroke="#fff" strokeWidth={2.5} />
- </span>
- )}
- {profile.isAdmin && (
- <span className="user-profile__badge user-profile__badge--admin" title="관리자">
- <Shield size={16} />
- </span>
- )}
- </h1>
- <p className="user-profile__handle">
- <span className="user-profile__handle-text">
- {profile.channelSID ? (
- <Link
- href={buildChannelUrl({ handle: profile.channelHandle, channelSID: profile.channelSID })}
- className="user-profile__handle-link"
- aria-label={`${handle} 크리에이터 채널로 이동`}
- >
- {handle}
- </Link>
- ) : (
- handle
- )}
- </span>
- </p>
- <p className="user-profile__counts">
- <Link href={`/user/${profile.memberSID}/followers`} className="user-profile__counts-link">
- <strong>{formatCount(profile.followerCount)}</strong> 팔로워
- </Link>
- <Link href={`/user/${profile.memberSID}/following`} className="user-profile__counts-link">
- <strong>{formatCount(profile.followingCount)}</strong> 팔로우
- </Link>
- <Link href={`/user/${profile.memberSID}`} className="user-profile__counts-link" aria-label={`게시물 ${profile.postCount + profile.feedPostCount}개 보기`}>
- <strong>{formatCount(profile.postCount + profile.feedPostCount)}</strong> 게시물
- </Link>
- </p>
- {profile.intro && (
- <div className="user-profile__intro" dangerouslySetInnerHTML={{ __html: profile.intro }} />
- )}
- </div>
- </header>
- );
- }
|